#include "fs.h"
#include "tty.h"
#include "string.h"
#include "syscall.h"
#include "vfs.h"
#include "slab.h"
#include "string.h"
#include "printk.h"
#include "list.h"
#include "config.h"
#include "unistd.h"
#include "fcntl.h"
#include "wait.h"
#include "socket.h"
#include "inet.h"
#include "inet_socket.h"
#include "interrupt.h"
#include "timer.h"
#include "completion.h"
#include "fork.h"
#include "mm.h"
#include "page.h"
#include "softirq.h"
#include "time.h"
#include "setup.h"

#include "asm/mmu_context.h"
#include "asm/processor.h"
#include "linux/compiler.h"
#include "linux/init.h"
#include "linux/sched.h"

void test_completion_func(void *x)
{
    complete(x);
}

struct completion test_done;
struct timer_list test_completion_timer = 
{
    .expires = 100,
    .data = &test_done,
    .function = test_completion_func
};

int test_completion(void *arg)
{
    init_completion(&test_done);
    add_timer(&test_completion_timer);
    printk("&test_completion_timer: %x\n", &test_completion_timer);
    printk("&test_done: %x\n", &test_done);
    while (1)
    {
        mod_timer(&test_completion_timer, 100);
        printk("Test completion test_done.done %d\n", test_done.done);
        wait_for_completion(&test_done);
    }
}

static void setup_command_line(char *command_line)
{

}

void parse_early_param(void)
{

}

extern void test_set_pgd(void);
extern void kmem_cache_init(void);
extern void kmem_cache_sizes_init(void);
extern void proc_caches_init(void);
extern void proc_caches_init(void);
extern void BOARD_InitMemory(void);
extern void driver_init(void);
extern int vfs_caches_init(void);

/*
 * Set up kernel memory allocators
 */
static void memory_init(void)
{
	mem_init(0x80000000, 0xa0000000);
	show_free_areas();
    
	kmem_cache_init();
    kmem_cache_sizes_init();
	
	//pgtable_init();
	//vmalloc_init();
	//ioremap_huge_init();
}



int do_one_initcall(initcall_t fn)
{
    int ret;

    ret = fn();

    return ret;
}

extern initcall_t __initcall_start[];
extern initcall_t __initcall0_start[];
extern initcall_t __initcall1_start[];
extern initcall_t __initcall2_start[];
extern initcall_t __initcall3_start[];
extern initcall_t __initcall4_start[];
extern initcall_t __initcall5_start[];
extern initcall_t __initcall6_start[];
extern initcall_t __initcall7_start[];
extern initcall_t __initcall_end[];

static initcall_t *initcall_levels[] __initdata = {
	__initcall0_start,
	__initcall1_start,
	__initcall2_start,
	__initcall3_start,
	__initcall4_start,
	__initcall5_start,
	__initcall6_start,
	__initcall7_start,
	__initcall_end,
};

void do_initcall_level(int level)
{
    initcall_t *fn;

    for (fn = initcall_levels[level]; fn < initcall_levels[level + 1]; fn ++)
        do_one_initcall(*fn);
}

void do_initcalls(void)
{
    int level;

    for (level = 0; level < sizeof (initcall_levels) / sizeof (initcall_levels[0]) - 1; level++)
        do_initcall_level(level);
}

void do_basic_setup(void)
{
	//cpuset_init_smp();
	//usermodehelper_init();
	//shmem_init();
	driver_init();
	//init_irq_proc();
	//do_ctors();
	//usermodehelper_enable();
	do_initcalls();
	//random_int_secret_init();
}

static void kernel_init_freeable(void)
{
    do_basic_setup();
}

int OS_IDLE_PROCESS(void *arg)
{
	while (1)
	{
		//printk("OS Idle Process\n");
	    schedule();
	}
}

/*
 * 尚未实现用户进程相关的功能，临时模拟
 */
int user_task(void* arg);
struct task_struct *alloc_task_struct_node(int node);
void ret_from_fork(void) __asm__("ret_from_fork");
void thread_exit(void);
void insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vmp);
static int run_init_process(char *init_filename, void *args)
{
    int fd_stdin, fd_stdout, fd_stderr;
	struct task_struct *tsk;
	struct pt_regs *ptregs;
	unsigned long stack_user;

	
	fd_stdin = sys_open("/dev/stdin", O_RDWR, 0666);
	if (fd_stdin < 0)
	{

	}
	
	fd_stdout = sys_open("/dev/stdout", O_RDWR, 0666);
	if (fd_stdout < 0)
	{

	}

	fd_stderr = sys_open("/dev/stderr", O_RDWR, 0666);
	if (fd_stderr < 0)
	{

	}

	tsk = current;
	tsk->flags &= ~(PF_KTHREAD);

	tsk->mm = mm_alloc();
	if (!tsk->mm)
	{

	}

	tsk->mm->pgd = pgd_alloc();

	// 用户栈,可以只设置值，真实物理页面可以在memory fault中申请
	stack_user = do_brk(0x20000000, 8192);
	if (!stack_user)
	{

	}

	ptregs = task_pt_regs(tsk);
	ptregs->ARM_r0 = (unsigned long)args;
	ptregs->ARM_sp = stack_user + 8192 - 8;
	ptregs->ARM_cpsr = SYSTEM_MODE; // 用户模式和系统模式使用同一套寄存器，这里使用系统模式为了方便调试
	ptregs->ARM_lr = (unsigned long)thread_exit;
	ptregs->ARM_pc = (unsigned long)user_task;

	switch_mm(NULL, tsk->mm, tsk); //这一步可以没有，放到memory fault中去做

	return 0;
}

int kernel_init(void *argv)
{
	local_irq_disable();

    kernel_init_freeable();

	//socket_init();
	//net_core_init();

	kernel_thread(OS_IDLE_PROCESS, NULL);

	local_irq_enable();

	run_init_process(NULL, NULL);

    return 0;
}

static void rest_init(void)
{
	int ret;

    ret = kernel_thread(kernel_init, (void *)0);
	if (ret < 0)
	{

	}

	schedule_preempt_disabled();
}

void start_kernel(void)
{
    char *command_line = (char *)0x80400000;
	//char *after_dashes;

	//lockdep_init();
	//set_task_stack_end_magic(&init_task);
	//smp_setup_processor_id();
	//debug_objects_early_init();

	//boot_init_stack_canary();
	//cgroup_init_early();

	//local_irq_disable();
	//early_boot_irqs_disabled = true;

	//boot_cpu_init();
	//page_address_init();
	//pr_notice("%s", linux_banner);
	setup_arch((void *)command_line);
	//mm_init_cpumask(&init_mm);
	setup_command_line(command_line);
	//setup_nr_cpu_ids();
	//setup_per_cpu_areas();
	//smp_prepare_boot_cpu();	/* arch-specific boot-cpu hooks */

	build_all_zonelists(NULL, NULL);
	page_alloc_init();

	//pr_notice("Kernel command line: %s\n", boot_command_line);
	parse_early_param();

    /*
	after_dashes = parse_args("Booting kernel",
				  static_command_line, __start___param,
				  __stop___param - __start___param,
				  -1, -1, &unknown_bootoption);
	if (!IS_ERR_OR_NULL(after_dashes))
		parse_args("Setting init args", after_dashes, NULL, 0, -1, -1,
			   set_init_arg);
    */

	//jump_label_init();

	//setup_log_buf(0);
	//pidhash_init();
	//vfs_caches_init_early();
	//sort_main_extable();
	//trap_init();
	memory_init();//mm_init

	sched_init();
	
    //preempt_disable();
	//if (WARN(!irqs_disabled(), "Interrupts were enabled *very* early, fixing it\n"))
	//local_irq_disable();
	//idr_init_cache();
	//rcu_init();

	/* trace_printk() and trace points may be used after this */
	//trace_init();

	//context_tracking_init();
	//radix_tree_init();
	/* init some links before init_ISA_irqs() */
	init_IRQ();
	//tick_init();
	//rcu_init_nohz();
	init_timers();
	//hrtimers_init();
	softirq_init();
	//timekeeping_init();
	time_init();
	//sched_clock_postinit();
	//perf_event_init();
	//profile_init();
	//call_function_init();
	//WARN(!irqs_disabled(), "Interrupts were enabled early\n");
	//early_boot_irqs_disabled = false;
	//local_irq_enable();

	//kmem_cache_init_late();

	console_init();
	//if (panic_later)
		//panic("Too many boot %s vars at `%s'", panic_later, panic_param);

	//lockdep_info();

	//locking_selftest();

	//page_ext_init();
	//debug_objects_mem_init();
	//kmemleak_init();
	//setup_per_cpu_pageset();
	//numa_policy_init();
	//if (late_time_init)
		//late_time_init();
	sched_clock_init();
	//calibrate_delay();
	//pidmap_init();
	//anon_vma_init();
	//acpi_early_init();
	thread_info_cache_init();
	//cred_init();
	fork_init();
	proc_caches_init();
	//buffer_init();
	//key_init();
	//security_init();
	//dbg_late_init();
	vfs_caches_init();
	//signals_init();
	//page_writeback_init();
	//proc_root_init();
	//nsfs_init();
	//cpuset_init();
	//cgroup_init();
	//taskstats_init_early();
	//delayacct_init();

	//check_bugs();

	//acpi_subsystem_init();
	//sfi_init_late();

	//if (efi_enabled(EFI_RUNTIME_SERVICES)) 
    //{
		//efi_late_init();
		//efi_free_boot_services();
	//}

	//ftrace_init();

	/* Do the rest non-__init'ed, we're now alive */
	rest_init();
}
